package com.chen.common.dataSource.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.chen.base.module.mybatis.config.DruidSqlLogFilter;
import com.chen.common.dataSource.constant.DataSourceConstant;
import com.chen.common.dataSource.property.DataSourceProperty;
import com.chen.common.dataSource.property.DruidPoolProperty;
import com.chen.common.dataSource.property.SpringDataSourceProperty;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 配置多数据源
 * @author ~龙~
 */
@Configuration
public class DynamicDataSourceConfig {

    @Resource
    DefaultListableBeanFactory beanFactory;
    @Resource
    SpringDataSourceProperty springDataSourceProperty;
    @Resource
    DruidSqlLogFilter druidSqlLogFilter;

    @Bean(DataSourceConstant.PRIMARY_DS)
    @ConfigurationProperties("spring.datasource.primary")
    public DataSource primaryDataSource() throws SQLException {
        DruidDataSource druidDataSource = DruidDataSourceBuilder.create().build();
        setDruidConfig(druidDataSource);
        return druidDataSource;
    }
 
    @Bean
    @Primary
    public DataSourceThreadLocal dataSource() throws SQLException {
        Map<Object, Object> dataSourceMap = new HashMap<>();
        for (DataSourceProperty dataSource : springDataSourceProperty.getDynamics()) {
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setDriverClassName(dataSource.getDriverClassName());
            druidDataSource.setUrl(dataSource.getUrl());
            druidDataSource.setUsername(dataSource.getUsername());
            druidDataSource.setPassword(dataSource.getPassword());
            druidDataSource.setProxyFilters(Collections.singletonList(druidSqlLogFilter));
            // Druid连接池配置
            setDruidConfig(druidDataSource);
            // 向IOC容器注册数据源：参数1-bean名称，参数2-bean对象
            beanFactory.registerSingleton(dataSource.getName(), druidDataSource);
            dataSourceMap.put(dataSource.getName(),druidDataSource);
        }

        return new DataSourceThreadLocal(primaryDataSource(), dataSourceMap);
    }

    @Bean
    public JdbcTemplate jdbcTemplate() throws SQLException {
        return new JdbcTemplate(primaryDataSource());
    }

    /**
     * （非必要）开启前台监控页面对应的 Servlet，并设置密码（通过 http://127.0.0.1:8092/druid/index.html 即可访问监控页面）
     * 此 Servlet 是由 Druid 提供的 StatViewServlet
     */
    @Bean
    public ServletRegistrationBean<StatViewServlet> druidServlet(){
        ServletRegistrationBean<StatViewServlet> servlet = new ServletRegistrationBean<>(
                new StatViewServlet(), "/druid/*"
        );
        DruidPoolProperty druid = springDataSourceProperty.getDruid();
        servlet.addInitParameter("loginUsername", druid.getUsername());
        servlet.addInitParameter("loginPassword", druid.getPassword());
        // 是否能够重置数据
        servlet.addInitParameter("resetEnable","false");
        return servlet;
    }

    /**
     * （非必要）配置Druid的Filter，用于记录 web 请求记录。
     * 此 Filter 是由 Druid 提供的 WebStatFilter
     */
    @Bean
    public FilterRegistrationBean<WebStatFilter> druidFilter(){
        FilterRegistrationBean<WebStatFilter> filter = new FilterRegistrationBean<>(new WebStatFilter());
        //添加过滤规则
        filter.addUrlPatterns("/*");
        // 除以下路径的访问不记录，其它都会进行记录
        filter.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filter;
    }

    private void setDruidConfig(DruidDataSource druidDataSource) throws SQLException {
        DruidPoolProperty druid = springDataSourceProperty.getDruid();
        druidDataSource.setInitialSize(druid.getInitialSize());
        druidDataSource.setMinIdle(druid.getMinIdle());
        druidDataSource.setMaxActive(druid.getMaxActive());
        druidDataSource.setMaxWait(druid.getMaxWait());
        druidDataSource.setTimeBetweenEvictionRunsMillis(druid.getTimeBetweenEvictionRunsMillis());
        druidDataSource.setMinEvictableIdleTimeMillis(druid.getMinEvictableIdleTimeMillis());
        druidDataSource.setValidationQuery(druid.getValidationQuery());
        druidDataSource.setTestWhileIdle(druid.getTestWhileIdle());
        druidDataSource.setTestOnBorrow(druid.getTestOnBorrow());
        druidDataSource.setTestOnReturn(druid.getTestOnReturn());
        druidDataSource.setFilters("stat,wall");
        // 慢sql记录
        Properties properties = new Properties();
        properties.setProperty("druid.stat.mergeSql", "true");
        properties.setProperty("druid.stat.slowSqlMillis", "2000");
        druidDataSource.setConnectProperties(properties);
    }
}